package flowshop.Bees;

import java.util.Random;

import flowshop.Solution.InputData;
import flowshop.Solution.Solution;

public class BeeColony {
	
	Solution[] solutions;
	int[] trials;
	BeeParameters bp = new BeeParameters();
	Random rand;
	InputData data;
	
	public BeeColony() {
		rand = new Random();
	}
	
	
	public double calculateFitness(double fun) {
		if(fun >= 0)
			return 1.0 / (1 + fun);
		return 1.0 + Math.abs(fun);
	}
	
	
	public void memorizeBestSolution() {}
	public void calculateProbabilities() {}
	
	public void sendEmployedBees() {
		int i;
		double r;

		double[] fitness = new double[bp.foodSourcesNumber];
		fitness[0] = 0.0;

		for (i = 0; i < bp.foodSourcesNumber; i++) {
			r = ((double) Math.random() * 32767) / (32767.0 + 1.0);

			int param2change = (int) (r * data.getMachines());

			Solution mutatedSolution = mutate(param2change);
			
			/**
			 * Zamiana sasiadujacych ze soba zadan
			 */
			
			int tmp;
			int iloscZadan = data.getMachines();
			for(int j=0;j<iloscZadan;j++){
				tmp = data.data[j][param2change];
				data.data[j][param2change] = data.data[j][(param2change + 1) % iloscZadan];
				data.data[j][(param2change + 1) % iloscZadan] = tmp;
				
			}
			
			r = ((double) Math.random() * 32767) / (32767.0 + 1.0);
			int neighbour = (int)(r * bp.foodSourcesNumber);
				
			mutatedSolution.getSolution()[param2change] = data.data[i][param2change] + (int) ((data.data[i][param2change] - data.data[neighbour][param2change])*(r-0.5)*2);

			if(mutatedSolution.getSolution()[param2change] < data.getLowerBound())
				mutatedSolution.getSolution()[param2change] = data.getLowerBound();
			if(mutatedSolution.getSolution()[param2change] > data.getUpperBound())
				mutatedSolution.getSolution()[param2change] = data.getUpperBound();	
			
			double mutantFitness = calculateFitness(calculateFunction(mutatedSolution));

			if (mutantFitness > fitness[i])
			{
				trials[i] = 0;
				fitness[i] = mutantFitness;
				solutions[i] = mutatedSolution.clone();
			} else {
				trials[i]++;
			}
		}
	}

	
	
	public void sendOnlookeerBees() {
		int i, t;
		i = t = 0;
		while ( t < bp.colonySize) {
			double probabiltiy = (double) Math.random() * 32767 / ((double) (32767) + 1.0);
			if (probabiltiy < getProbability(i) ) {
				t++;
				Solution mutated = mutate(i);
				
				if (mutated.getEval() >= solutions[i].getEval() ) {
					trials[i]++;
				} else {
					solutions[i] = mutated.clone();
					trials[i] = 0;
				}
				i++;
				if ( i >= bp.colonySize ) {
					i = 0;
				}
			}
		}
	}
	public void sendScoutBees() {}
	
	public Solution mutate(int index) {
		int t1, t2;
		t1 = rand.nextInt(data.getJobs());
		t2 = rand.nextInt(data.getJobs());
		
		int[] mutated = new int[data.getJobs()];
		
		while ( t1 == t2 ) {
			t2 = rand.nextInt(data.getJobs()); 
		}
		
		for (int i = 0; i < data.getJobs(); i++) {
			mutated[i] = solutions[index].getSolution()[i];
		}
		
		int tmp = mutated[t1];
		mutated[t1] = mutated[t2];
		mutated[t2] = tmp;
		
		return new Solution(data, mutated);
		
		
	}
	
	public double getProbability(int index) {
		return 0.0;
	}
	
	
	private double calculateFunction(Solution solution){
		double ret = 0;
		
		int []sol = solution.getSolution();
		
		for(int i=0;i<data.getMachines();i++)
			ret += Math.pow(sol[i], 2.0) + 10 - 10*Math.cos(2 * Math.PI * sol[i]);
		
		return ret;
	}
	
}

/**
 * klasa z elementami kontrolnymi
 */
class BeeParameters {
	
	/* rozmiar kolonii = (employedBees + onlookerBees) */
	public int colonySize;
	
	/* ilosc zrodel pozywienia, domyslnie przyjmiemy colonySize/2 */
	public int foodSourcesNumber;
	
	/* ilosc cykli eksploracyjnych - kryterium stopu */
	public int maxCycle;
	
	protected BeeParameters() {}
}
